package com.atguigu.srb.core.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.guli.common.util.HttpClientUtils;
import com.atguigu.srb.base.exception.SrbException;
import com.atguigu.srb.base.result.ResponseEnum;
import com.atguigu.srb.base.util.JwtUtils;
import com.atguigu.srb.base.util.SrbAssert;
import com.atguigu.srb.core.config.WxLoginProperties;
import com.atguigu.srb.core.pojo.entity.UserInfo;
import com.atguigu.srb.core.service.UserInfoService;
import com.atguigu.srb.core.service.UserLoginRecordService;
import com.atguigu.srb.core.service.WxLoginService;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.apache.commons.compress.utils.Charsets;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.net.URLEncoder;
import java.text.ParseException;
import java.util.Map;
import java.util.UUID;

@Service
public class WxLoginServiceImpl implements WxLoginService {
    @Resource
    UserInfoService userInfoService;
    @Resource
    UserLoginRecordService userLoginRecordService;
    @Override
    public String wxLogin(HttpSession session) {
        /*
    # 微信开放平台 appid
    appId: wxed9954c01bb89b47
    # 微信开放平台 appsecret
    appSecret: a7482517235173ddb4083788de60b90e
    # 微信开放平台 重定向url(localhost:8160 必须和wx平台配置的授权回调域一致)
    redirectUri: http://localhost:8160/api/ucenter/wx/callback
 */
        String token = UUID.randomUUID().toString();
        /*
            浏览器提交请求，服务器初始化session对象
                        设置jsessionid作为cookie到响应头中
                        将jsessionid和session保存到服务器内存中(SessionMap)
            浏览器接收到响应时，如果cookie中有值，会自动获取保存
                        cookie没有设置过期时间，则保存在运行内存中(jsessionid)

            浏览器再次提交请求自动携带cookie，服务器可以根据请求报文中jsessionid的cookie
                        获取自己内存中SessionMap中 jsessionid的值session对象
         */
        //session共享token：会话域  在一次会话期间共享数据(浏览器打开到关闭)
        session.setAttribute("token",token);
        return "redirect:"+ WxLoginProperties.API_URL +//wx二维码接口地址
                "?appid="+ WxLoginProperties.APP_ID +//我们的应用注册到wx平台时分配的唯一id
                //用户扫码授权后wx让浏览器重定向访问的回调接口地址
                // 因为应用在wx平台注册时设置的回调服务器域名是localhost:8160 此处必须写8160
                /*
                    wx官方文档建议 redirect_uri的值 使用URLEncoder编码处理

//http://localhost:9528/#/integral-grade/list?username=%E5%BC%A0%E7%9B%8A%E6%A1%83abcd
                    BASE64：
                    UrlEncode：
                        以上两种编码方式都是为了乱码问题:
                            浏览器和服务器交互时一般使用UrlEncode解决
                            服务端 一般使用Base64
                 */
                "&redirect_uri="+ URLEncoder.encode(WxLoginProperties.WX_REDIRECT_URI) +
                "&response_type=code" +
                "&scope=snsapi_login" + //wx登录授权后的token的作用域
                "&state="+token+
                "#wechat_redirect";

    }

    @Override
    public String callback(String code, String state, HttpSession session, HttpServletRequest request) {
        //校验state值：
        Object sessionToken = session.getAttribute("token");
        SrbAssert.assertNotTrue(StringUtils.isEmpty(state)|| sessionToken==null
                || !state.equals(sessionToken), ResponseEnum.WX_LOGIN_CALLBACK_TOKEN_ERROR);
        //销毁使用过的token
        session.removeAttribute("token");
        System.out.println("回调接口被访问了...");
        //1、通过code获取access_token
        String path = WxLoginProperties.CALLBACK_URL +
                "?appid="+ WxLoginProperties.APP_ID +
                "&secret="+ WxLoginProperties.SECRET +
                "&code="+ code +
                "&grant_type=authorization_code";
        HttpClientUtils client = new HttpClientUtils(path);
        //发起请求
        UserInfo userInfo = null;
        try {
            client.get();
            //获取响应体中的json字符串
            String result = client.getContent();
            //将响应结果转为Map
            Map<String,Object> map = JSON.parseObject(result, Map.class);
            //判断响应是否成功
            if(result.contains("errcode")){
                throw new SrbException(map.get("errmsg").toString(),
                        Integer.parseInt(map.get("errcode").toString()));
            }
            //获取code换取的授权凭证token
            String accessToken = map.get("access_token").toString();
            //wx登录授权的wx用户的openid(每个用户wx的openid唯一)
            String openid = map.get("openid").toString();
//3、根据openid查询wx用户数据如果不存在将wx登录的用户转化为我们自己的用户保存到数据库
            userInfo = userInfoService.getOne(Wrappers.lambdaQuery(UserInfo.class)
                    .eq(UserInfo::getOpenid, openid));
            //System.out.println((System.currentTimeMillis()-userInfo.getUpdateTime().getTime())>=7*24*60*60*1000);
            if(userInfo==null){
                //2、使用access_token获取wx用户的个人信息
                map = getWxUserInfo(accessToken, openid);
                //获取wx用户信息成功
                String nickname = map.get("nickname").toString();
                String headimgurl = map.get("headimgurl").toString();
                userInfo = new UserInfo();//id雪花算法生成
                userInfo.setNickName(nickname);
                userInfo.setOpenid(openid);
                userInfo.setHeadImg(headimgurl);
                userInfo.setIntegral(0);
                userInfo.setSalt("wx");//salt数据库表字段不能为空
                userInfoService.save(userInfo);
            }else if((System.currentTimeMillis()-userInfo.getUpdateTime().getTime())>=7*24*60*60*1000){
                //2、使用access_token获取wx用户的个人信息
                map = getWxUserInfo(accessToken, openid);
                //获取wx用户信息成功
                String nickname = map.get("nickname").toString();
                String headimgurl = map.get("headimgurl").toString();
                userInfo.setNickName(nickname);
                userInfo.setHeadImg(headimgurl);
                userInfoService.updateById(userInfo);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new SrbException(ResponseEnum.WEIXIN_CALLBACK_PARAM_ERROR);
        }
        //如果wx用户保存到数据库的数据超过7天更新wx用户的数据 到数据库中
        //保存登录日志
        userLoginRecordService.saveLoginLogs(request, userInfo,2);
        //4、将wx用户的数据展示到登录成功页面(http://localhost:3000)
        //让浏览器重定向访问http://localhost:3000?token=xxxx
        String token = JwtUtils.createToken(userInfo.getId(),userInfo.getNickName());
        //首页将来根据token解析到id 查询对应的userInfo数据：
        return "redirect:"+ WxLoginProperties.REDIRECT_URL+"?token="+token;
    }

    public Map<String, Object> getWxUserInfo(String accessToken, String openid) throws IOException, ParseException {
        String path;
        HttpClientUtils client;
        String result;
        Map<String, Object> map;
        path = WxLoginProperties.USERINFO_URL +
                "?access_token=" + accessToken +
                "&openid=" + openid;
        client = new HttpClientUtils(path);
        client.get();
        result = client.getContent();
        map = JSON.parseObject(result, Map.class);
        if (result.contains("errcode")) {
            throw new SrbException(map.get("errmsg").toString(),
                    Integer.parseInt(map.get("errcode").toString()));
        }
        return map;
    }
}
